
#ifndef __U_MSG_H_
#define __U_MSG_H_


#define SYS_UMSG        0x11
#define SYS_PIOS        0x22


typedef struct _tag_umsg {
	
    struct _tag_umsg * next;
    
    uint8_t rsvd22;
    uint8_t offs;
    uint8_t mlen;
    uint8_t type;

    uint8_t data[64];

} umsg_t;


int umsg_init( int num );


int sysmsg_send_to_user( int tcnt, uint32_t * pary );
int symsg_recv_from_system( int tcnt, uint32_t * pary );


//
int umsg_inp_cbk( void * parg, uint8_t * ptr, int tmax );
int umsg_outp_cbk( void * parg, uint8_t * ptr, int tsiz );


/*
 * queue, fifo.
 */

typedef struct _tag_queue {
    umsg_t * tail;
    umsg_t head;
} uqueue_t;


static inline void umsg_q_init( uqueue_t * pque )
{
    pque->head.next = &(pque->head);
    pque->tail = &(pque->head);
    pque->head.rsvd22 = 0;
}


static inline void umsg_q_enque( uqueue_t * pque, umsg_t * pnd )
{
    pnd->next = &(pque->head);
    pque->tail->next = pnd;
    pque->tail = pnd;

    pque->head.rsvd22 += 1;
}


static inline umsg_t * umsg_q_deque( uqueue_t * pque )
{
    umsg_t * pnd;

    if ( pque->head.next == &(pque->head) ) {
        return NULL;
    }

    pnd = pque->head.next;    
    pque->head.next = pnd->next;
    pque->head.rsvd22 -= 1;

    if ( pque->head.next == &(pque->head) ) {
        pque->tail = &(pque->head);
    }

    return pnd;
}


static inline bool umsg_q_is_empty( uqueue_t * pque )
{
    if ( pque->head.next == &(pque->head) ) {
        return true;
    } else {
        return false;
    }
}


/**/
umsg_t * umsg_alloc( void );
void umsg_free( umsg_t * pnd );


#if 0

/*
 * user 调用, 获得从 host 下发来的消息.
 * 执行 syscall, 自动屏蔽其他中断.
 * 如果没有消息, 不会阻塞, 返回 NULL.
 */
static inline umsg_t * umsg_recv(void) {
  register umsg_t *pmsg __asm("r0");
  __ASM volatile("SVC #2": "=r"(pmsg) :  : "memory" );
  return pmsg;
}

#endif


/*
 * 执行 syscall.
 * 如果 usb buffer 满状态, 会临时构成单链表, 不会阻塞..
 */
static inline void umsg_send( umsg_t * pmsg )
{ 
    pmsg->data[0] = pmsg->type | 0x80;
    pmsg->mlen = pmsg->offs;
    
    /**/
    __ASM volatile ( "MOV r0, %0; SVC #3" : : "r"(pmsg) : "memory" );
    return;
}


static inline void umsg_dbg_send( umsg_t * pmsg )
{ 
    pmsg->data[0] = 0;
    pmsg->mlen = pmsg->offs;
    
    /**/
    __ASM volatile ( "MOV r0, %0; SVC #3" : : "r"(pmsg) : "memory" );
    return;
}


static inline void umsg_fwd_send( umsg_t * pmsg )
{
    /* 开始字节是 type, 规定 DUT 使用的范围是 [0x40 - 0x7F] */
    pmsg->data[0] = 0x40 | pmsg->data[0];
    pmsg->mlen = pmsg->offs;
    
    /**/
    __ASM volatile ( "MOV r0, %0; SVC #3" : : "r"(pmsg) : "memory" );
    return;
}



/**/
static inline void umsg_reset_ofs( umsg_t * pmsg )
{
    /* 用户代码的 read 和 write 处理, 跳过 type 字节.. */
    pmsg->offs = 1;
    return;
}


static inline uint8_t umsg_get_u8( umsg_t * pmsg )
{
    int ofs = pmsg->offs;

    /**/
    pmsg->offs += 1;
    return pmsg->data[ofs];
}


static inline uint16_t umsg_get_u16( umsg_t * pmsg )
{
    int ofs = pmsg->offs;
    uint16_t temp;

    /**/
    temp = pmsg->data[ofs + 1];
    temp = (temp << 8) | pmsg->data[ofs];

    /**/
    pmsg->offs += 2;
    return temp;
}



static inline uint32_t umsg_get_u32( umsg_t * pmsg )
{
    int ofs = pmsg->offs;
    uint32_t temp;

    /**/
    temp = pmsg->data[ ofs + 3 ];
    temp = ( temp << 8 ) | pmsg->data[ ofs + 2 ];
    temp = ( temp << 8 ) | pmsg->data[ ofs + 1 ];
    temp = ( temp << 8 ) | pmsg->data[ ofs ];

    /**/
    pmsg->offs += 4;
    return temp;
}


static inline int32_t umsg_get_i32( umsg_t * pmsg ) {
    return (int32_t)umsg_get_u32( pmsg );
}


static inline uintptr_t umsg_get_ptr( umsg_t * pmsg ) {
    return (uintptr_t)umsg_get_u32( pmsg );   
}

/*
还没有读出的 剩余数据 长度.
*/
static inline int umsg_remains( umsg_t * pmsg )
{
    return (int)( (uint16_t)pmsg->mlen - pmsg->offs );
}

/*
让 offset 跳过一些数据(空间).
在读数据场景中, 用于跳过一些不关心的内容.
也可以用于写数据场景中, 为了对齐下一个字段而添加 padding.
*/
static inline void umsg_skip( umsg_t * pmsg, int tsiz )
{
    pmsg->offs += tsiz;
    return;
}


static inline void * umsg_curr( umsg_t * pmsg )
{
    return (void *)( pmsg->data + pmsg->offs );
}


static inline void umsg_add_u8( umsg_t * pmsg, uint8_t uv )
{
    int ofs = pmsg->offs;

    pmsg->data[ ofs ] = uv;
    pmsg->offs = ofs + 1;
    return;
}


static inline void umsg_add_u16( umsg_t * pmsg, uint16_t uv )
{
    int ofs = pmsg->offs;

    pmsg->data[ ofs ] = uv & 0xFF;
    pmsg->data[ ofs + 1 ] = (uv >> 8) & 0xFF;
    pmsg->offs = ofs + 2;
    return;
}


static inline void umsg_add_u24( umsg_t * pmsg, uint32_t uv )
{
    int ofs = pmsg->offs;

    pmsg->data[ ofs ] = uv & 0xFF;
    pmsg->data[ ofs + 1 ] = (uv >> 8) & 0xFF;
    pmsg->data[ ofs + 2 ] = (uv >> 16) & 0xFF;
    
    pmsg->offs = ofs + 3;
    return;
}


/* pack data to umsg */
static inline void umsg_add_u32( umsg_t * pmsg, uint32_t uv )
{
    int ofs = pmsg->offs;

    /* little endian */
    pmsg->data[ ofs ] = uv & 0xFF;
    pmsg->data[ ofs + 1 ] = (uv >> 8) & 0xFF;
    pmsg->data[ ofs + 2 ] = (uv >> 16) & 0xFF;
    pmsg->data[ ofs + 3 ] = (uv >> 24) & 0xFF;

    /**/
    pmsg->offs = ofs + 4;
    return;
}


static inline void umsg_add_i32( umsg_t * pmsg, int32_t iv )
{
    umsg_add_u32( pmsg, (uint32_t)iv );
    return;
}



#endif


